#!/bin/bash

set -e

# Check if running under systemd-inhibit
if [[ -z "$SYSTEMD_INHIBIT_RUNNING" ]]; then
    # Prevent system suspend while the entire script is running
    export SYSTEMD_INHIBIT_RUNNING=1
    exec systemd-inhibit --who="cjbuild" --why="Building Cangjie" --mode=block "$0" "$@"
fi

# Start time measurement
START_TIME=$(date +%s)

# Set MY_ROOT to the normalized absolute current directory
CURRENT_DIR=$(pwd -P)

# Function to find the project root by looking for known directories
find_project_root() {
    local dir="$1"
    local max_depth=5
    local depth=0
    
    while [[ "$depth" -lt "$max_depth" && "$dir" != "/" ]]; do
        # Check if this directory contains the main project components
        if [[ -d "$dir/cangjie_compiler" && -d "$dir/cangjie_runtime" ]]; then
            echo "$dir"
            return 0
        fi
        dir=$(dirname "$dir")
        ((depth++))
    done
    
    echo "$CURRENT_DIR"  # Fallback to current directory
    return 1
}

# Find the actual project root
MY_ROOT=$(find_project_root "$CURRENT_DIR")
echo "Project root: $MY_ROOT"

# Default values
BUILD_TYPE="debug"
CLEAN_BUILD=false
BUILD_GCC_TOOLCHAIN="${BUILD_GCC_TOOLCHAIN:-}"

# Help function
show_help() {
    cat << EOF
Usage: $0 [OPTIONS]

Build Cangjie compiler, runtime, stdlib, and tools.

OPTIONS:
    -h, --help                      Show this help message and exit
    --clean                         Perform clean build (run build.py clean)
    -t, --build-type BUILD_TYPE     Set build type (debug, release, relwithdebinfo)
    --gcc-toolchain PATH            Set GCC toolchain path (overrides environment)

EXAMPLES:
    $0                              # Default debug build
    $0 --clean                      # Clean debug build
    $0 -t release                   # Release build
    $0 --clean -t relwithdebinfo    # Clean relwithdebinfo build
    $0 --gcc-toolchain /path/to/gcc # Use specific GCC toolchain
EOF
}

# Function to calculate and display elapsed time
show_elapsed_time() {
    local end_time=$1
    local start_time=$2
    local total_seconds=$((end_time - start_time))
    local minutes=$((total_seconds / 60))
    local seconds=$((total_seconds % 60))
    
    if [ $minutes -eq 0 ]; then
        echo "Total time: ${seconds}s"
    else
        echo "Total time: ${minutes}m ${seconds}s"
    fi
}

# Parse command-line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        --clean)
            CLEAN_BUILD=true
            shift
            ;;
        -t|--build-type)
            BUILD_TYPE="$2"
            if [[ ! "$BUILD_TYPE" =~ ^(debug|release|relwithdebinfo)$ ]]; then
                echo "Error: Invalid build type '$BUILD_TYPE'. Must be one of: debug, release, relwithdebinfo"
                exit 1
            fi
            shift 2
            ;;
        --gcc-toolchain)
            BUILD_GCC_TOOLCHAIN="$2"
            shift 2
            ;;
        *)
            echo "Error: Unknown option $1"
            show_help
            exit 1
            ;;
    esac
done

echo "Build configuration:"
echo "  BUILD_TYPE: $BUILD_TYPE"
echo "  CLEAN_BUILD: $CLEAN_BUILD"
echo "  BUILD_GCC_TOOLCHAIN: ${BUILD_GCC_TOOLCHAIN:-not set}"

# Define directories to check (required)
REQUIRED_DIRECTORIES=(
    "$MY_ROOT/cangjie_compiler"
    "$MY_ROOT/cangjie_runtime/runtime"
    "$MY_ROOT/cangjie_runtime/stdlib"
)

# Optional directories
OPTIONAL_DIRECTORIES=(
    "$MY_ROOT/cangjie_stdx"
    "$MY_ROOT/cangjie_tools/cjpm"
)

# Function to check directory existence
check_directories() {
    echo "Checking required directories..."
    local all_exist=true

    for dir in "${REQUIRED_DIRECTORIES[@]}"; do
        if [ -d "$dir" ]; then
            echo "  ✅ $dir"
        else
            echo "  ❌ $dir"
            all_exist=false
        fi
    done

    if [ "$all_exist" = false ]; then
        echo ""
        echo "Error: One or more required directories are missing."
        echo "Please ensure the Cangjie project structure is correct."
        echo "Current project root: $MY_ROOT"
        exit 1
    else
        echo "All required directories found."
    fi

    echo ""
    echo "Checking optional directories..."
    for dir in "${OPTIONAL_DIRECTORIES[@]}"; do
        if [ -d "$dir" ]; then
            echo "  ✅ $dir (will be built)"
        else
            echo "  ⚠️  $dir (optional, skipping)"
        fi
    done
    echo ""
}

# Function to get version and check compatibility for clang
validate_clang_version() {
    if ! command -v clang &> /dev/null; then
        echo "❌ Error: clang command not found"
        return 1
    fi

    local CLANG_VERSION=$(clang --version | head -1 | grep -oP 'clang version \K(\d+\.\d+\.\d+)' | head -1)
    if [ -z "$CLANG_VERSION" ]; then
        CLANG_VERSION=$(clang --version | head -1 | grep -oP 'version \K(\d+\.\d+\.\d+)' | head -1)
    fi

    # Extract clang major, minor, and patch versions
    local CLANG_MAJOR=$(echo $CLANG_VERSION | cut -d. -f1)
    local CLANG_MINOR=$(echo $CLANG_VERSION | cut -d. -f2)
    local CLANG_PATCH=$(echo $CLANG_VERSION | cut -d. -f3)

    # Check if clang version is in range [15.0.0, 16.0.0)
    if [ "$CLANG_MAJOR" -lt 15 ] || ([ "$CLANG_MAJOR" -eq 15 ] && [ "$CLANG_MINOR" -lt 0 ]) || ([ "$CLANG_MAJOR" -eq 15 ] && [ "$CLANG_MINOR" -eq 0 ] && [ "$CLANG_PATCH" -lt 0 ]); then
        echo "❌ Error: clang version $CLANG_VERSION is less than 15.0.0"
        echo "This build requires clang version >= 15.0.0 and < 16.0.0"
        return 1
    fi

    if [ "$CLANG_MAJOR" -ge 16 ]; then
        echo "❌ Error: clang version $CLANG_VERSION is 16.0.0 or greater"
        echo "This build requires clang version >= 15.0.0 and strictly less than 16.0.0"
        return 1
    fi

    echo "✅ Clang version $CLANG_VERSION is compatible"
    return 0
}

# Function to get version and check compatibility for g++
validate_gpp_version() {
    local gpp_cmd="g++"
    
    # Use GCC toolchain g++ if specified
    if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
        gpp_cmd="$BUILD_GCC_TOOLCHAIN/bin/g++"
        if [ ! -f "$gpp_cmd" ]; then
            echo "❌ Error: GCC toolchain g++ not found: $gpp_cmd"
            return 1
        fi
    fi

    if ! command -v "$gpp_cmd" &> /dev/null; then
        echo "❌ Error: g++ command not found: $gpp_cmd"
        return 1
    fi

    local GPP_VERSION=$("$gpp_cmd" --version | head -1 | grep -oP '(\d+\.\d+\.\d+)' | head -1)

    if [ -z "$GPP_VERSION" ]; then
        echo "❌ Error: Could not determine g++ version from: $gpp_cmd"
        return 1
    fi

    # Extract major and minor version for comparison
    local GPP_MAJOR=$(echo $GPP_VERSION | cut -d. -f1)
    local GPP_MINOR=$(echo $GPP_VERSION | cut -d. -f2)

    # Check if version is greater than 12.5
    if [ "$GPP_MAJOR" -gt 12 ] || ([ "$GPP_MAJOR" -eq 12 ] && [ "$GPP_MINOR" -gt 5 ]); then
        echo "❌ Error: g++ version $GPP_VERSION is greater than 12.5"
        echo "This build requires g++ version 12.5 or earlier"
        echo ""
        echo "To resolve this, you can:"
        echo "1. Pass the --gcc-toolchain option:"
        echo "   $0 --gcc-toolchain PATH_TO_GCC_12"
        echo "2. Or set the BUILD_GCC_TOOLCHAIN environment variable:"
        echo "   export BUILD_GCC_TOOLCHAIN=\$HOME/xpack-gcc-12.5.0-1"
        echo "   $0"
        echo ""
        echo "Example:"
        echo "   $0 --gcc-toolchain \$HOME/xpack-gcc-12.5.0-1"
        return 1
    fi

    if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
        echo "✅ GCC toolchain g++ version $GPP_VERSION is compatible"
    else
        echo "✅ g++ version $GPP_VERSION is compatible"
    fi
    return 0
}

# Function to check tool with version extraction
check_tool_version() {
    local tool=$1
    local version_pattern=${2:-'(\d+\.\d+\.\d+)'}
    local tool_cmd="$tool"
    
    # Use GCC toolchain binaries if specified
    if [ -n "$BUILD_GCC_TOOLCHAIN" ] && [[ "$tool" == "gcc" || "$tool" == "g++" ]]; then
        tool_cmd="$BUILD_GCC_TOOLCHAIN/bin/$tool"
        if [ ! -f "$tool_cmd" ]; then
            echo "  ❌ $tool (not found in toolchain: $tool_cmd)"
            return 1
        fi
    fi

    if command -v "$tool_cmd" &> /dev/null; then
        local version=$("$tool_cmd" --version 2>/dev/null | head -1 | grep -oP "$version_pattern" | head -1)
        if [ -n "$version" ]; then
            if [ -n "$BUILD_GCC_TOOLCHAIN" ] && [[ "$tool" == "gcc" || "$tool" == "g++" ]]; then
                echo "  ✅ $tool (toolchain): $version"
            else
                echo "  ✅ $tool: $version"
            fi
        else
            if [ -n "$BUILD_GCC_TOOLCHAIN" ] && [[ "$tool" == "gcc" || "$tool" == "g++" ]]; then
                echo "  ✅ $tool (toolchain): (version unknown)"
            else
                echo "  ✅ $tool: (version unknown)"
            fi
        fi
        return 0
    else
        echo "  ❌ $tool (not found)"
        return 1
    fi
}

# Function to setup compiler environment
setup_compiler_environment() {
    echo "Setting up compiler environment..."
    
    # Conditionally set GCC toolchain option
    if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
        GCC_TOOLCHAIN_OPTION="--gcc-toolchain $BUILD_GCC_TOOLCHAIN"
    else
        GCC_TOOLCHAIN_OPTION=""
    fi

    # Build compiler if not already built
    if [ ! -f "$MY_ROOT/cangjie_compiler/output/envsetup.sh" ]; then
        echo "Building compiler (required for current project)..."
        cd $MY_ROOT/cangjie_compiler
        if [ "$CLEAN_BUILD" = true ]; then
            ./build.py clean
        fi
        ./build.py build -j 12 -t $BUILD_TYPE --no-tests $GCC_TOOLCHAIN_OPTION
        ./build.py install
    fi
    
    # Source compiler environment
    source $MY_ROOT/cangjie_compiler/output/envsetup.sh
    
    # Set CCC override if needed
    if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
        export CCC_OVERRIDE_OPTIONS="^--gcc-toolchain=$BUILD_GCC_TOOLCHAIN"
    fi
    
    echo "✅ Compiler environment setup completed"
}

# Function to detect current project
detect_current_project() {
    local current_dir="$CURRENT_DIR"
    
    if [[ "$current_dir" == "$MY_ROOT/cangjie_compiler"* ]]; then
        echo "compiler"
    elif [[ "$current_dir" == "$MY_ROOT/cangjie_runtime/runtime"* ]]; then
        echo "runtime"
    elif [[ "$current_dir" == "$MY_ROOT/cangjie_runtime/stdlib"* ]]; then
        echo "stdlib"
    elif [[ "$current_dir" == "$MY_ROOT/cangjie_stdx"* ]]; then
        echo "stdx"
    elif [[ "$current_dir" == "$MY_ROOT/cangjie_tools/cjpm"* ]]; then
        echo "cjpm"
    else
        echo "all"
    fi
}

# Check if CANGJIE_HOME is already set
if [ -n "$CANGJIE_HOME" ]; then
    echo "❌ Error: CANGJIE_HOME is already set to: $CANGJIE_HOME"
    echo "Please do not run this build under another cangjie environment"
    echo "Recommend starting a fresh shell session"
    exit 1
fi

# If BUILD_GCC_TOOLCHAIN is set, add its bin directory to PATH early so tools are found
if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
    if [ -d "$BUILD_GCC_TOOLCHAIN/bin" ]; then
        export PATH="$BUILD_GCC_TOOLCHAIN/bin:$PATH"
        echo "✅ Added $BUILD_GCC_TOOLCHAIN/bin to PATH"
    else
        echo "❌ Error: GCC toolchain bin directory not found: $BUILD_GCC_TOOLCHAIN/bin"
        exit 1
    fi
fi

# Check for required tools with version information
echo "Checking build tools..."
check_tool_version "python3" 'Python (\d+\.\d+\.\d+)' || exit 1
check_tool_version "cmake" 'cmake version (\d+\.\d+\.\d+)' || exit 1

echo ""

# Validate compiler versions
echo "Validating compiler versions..."
validate_clang_version || exit 1
validate_gpp_version || exit 1
echo ""

# Detect current project
CURRENT_PROJECT=$(detect_current_project)
echo "Current directory: $CURRENT_DIR"
echo "Detected project: $CURRENT_PROJECT"
echo ""

# Build based on current project
case $CURRENT_PROJECT in
    "compiler")
        # Build compiler only
        echo "Building only compiler (current project)..."
        cd $MY_ROOT/cangjie_compiler
        if [ "$CLEAN_BUILD" = true ]; then
            ./build.py clean
        fi
        
        # Conditionally set GCC toolchain option
        if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
            GCC_TOOLCHAIN_OPTION="--gcc-toolchain $BUILD_GCC_TOOLCHAIN"
        else
            GCC_TOOLCHAIN_OPTION=""
        fi
        
        ./build.py build -j 12 -t $BUILD_TYPE --no-tests $GCC_TOOLCHAIN_OPTION
        ./build.py install
        source output/envsetup.sh
        echo "✅ Compiler build completed"
        ;;

    "runtime")
        # Build compiler first, then runtime
        setup_compiler_environment
        echo "Building only runtime (current project)..."
        cd $MY_ROOT/cangjie_runtime/runtime
        if [ "$CLEAN_BUILD" = true ]; then
            python3 build.py clean
        fi
        python3 build.py build -t $BUILD_TYPE
        python3 build.py install
        python3 build.py install --prefix $CANGJIE_HOME
        echo "✅ Runtime build completed"
        ;;

    "stdlib")
        # Build compiler first, then stdlib
        setup_compiler_environment
        echo "Building only stdlib (current project)..."
        cd $MY_ROOT/cangjie_runtime/stdlib
        if [ "$CLEAN_BUILD" = true ]; then
            ./build.py clean
        fi
        ./build.py build -t $BUILD_TYPE --target-lib=$MY_ROOT/cangjie_runtime/runtime/output
        ./build.py install --prefix $CANGJIE_HOME
        echo "✅ Stdlib build completed"
        ;;

    "stdx")
        # Build compiler first, then stdx
        setup_compiler_environment
        echo "Building only stdx (current project)..."
        cd $MY_ROOT/cangjie_stdx
        if [ "$CLEAN_BUILD" = true ]; then
            ./build.py clean
        fi
        # Check if the include directory exists
        if [ -d "$MY_ROOT/cangjie_compiler/include" ]; then
            ./build.py build -t $BUILD_TYPE --include=$MY_ROOT/cangjie_compiler/include
            ./build.py install
            echo "✅ Stdx build completed"

            CANGJIE_STDX_PATH=$(find target -name stdx | grep static | head -n1)
            CANGJIE_STDX_PATH="$(pwd -P)/$CANGJIE_STDX_PATH"
            export CANGJIE_STDX_PATH
        else
            echo "❌ Error: cangjie_compiler/include directory not found, required for stdx build"
            exit 1
        fi
        ;;

    "cjpm")
        # Build compiler first, then cjpm
        setup_compiler_environment
        echo "Building only cjpm tools (current project)..."
        cd $MY_ROOT/cangjie_tools/cjpm
        if [ "$CLEAN_BUILD" = true ]; then
            python3 build/build.py clean
        fi
        python3 build/build.py build -t $BUILD_TYPE
        python3 build/build.py install
        python3 build/build.py install --prefix $CANGJIE_HOME/tools/bin
        echo "✅ cjpm tools build completed"
        ;;

    "all")
        # Build everything (original behavior)
        check_directories
        
        # Build compiler
        echo "Building compiler..."
        cd $MY_ROOT/cangjie_compiler
        if [ "$CLEAN_BUILD" = true ]; then
            ./build.py clean
        fi
        
        # Conditionally set GCC toolchain option
        if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
            GCC_TOOLCHAIN_OPTION="--gcc-toolchain $BUILD_GCC_TOOLCHAIN"
        else
            GCC_TOOLCHAIN_OPTION=""
        fi
        
        ./build.py build -j 12 -t $BUILD_TYPE --no-tests $GCC_TOOLCHAIN_OPTION
        ./build.py install
        source output/envsetup.sh
        echo "✅ Compiler build completed"

        if [ -n "$BUILD_GCC_TOOLCHAIN" ]; then
            export CCC_OVERRIDE_OPTIONS="^--gcc-toolchain=$BUILD_GCC_TOOLCHAIN"
        fi

        # Build runtime
        echo "Building runtime..."
        cd $MY_ROOT/cangjie_runtime/runtime
        if [ "$CLEAN_BUILD" = true ]; then
            python3 build.py clean
        fi
        python3 build.py build -t $BUILD_TYPE
        python3 build.py install
        python3 build.py install --prefix $CANGJIE_HOME
        echo "✅ Runtime build completed"

        # Build std
        echo "Building stdlib..."
        cd $MY_ROOT/cangjie_runtime/stdlib
        if [ "$CLEAN_BUILD" = true ]; then
            ./build.py clean
        fi
        ./build.py build -t $BUILD_TYPE --target-lib=$MY_ROOT/cangjie_runtime/runtime/output
        ./build.py install --prefix $CANGJIE_HOME
        echo "✅ Stdlib build completed"

        # Build stdx (optional)
        if [ -d "$MY_ROOT/cangjie_stdx" ]; then
            echo "Building stdx (optional)..."
            cd $MY_ROOT/cangjie_stdx
            if [ "$CLEAN_BUILD" = true ]; then
                ./build.py clean
            fi
            # Check if the include directory exists
            if [ -d "$MY_ROOT/cangjie_compiler/include" ]; then
                ./build.py build -t $BUILD_TYPE --include=$MY_ROOT/cangjie_compiler/include
                ./build.py install
                echo "✅ Stdx build completed"

                CANGJIE_STDX_PATH=$(find target -name stdx | grep static | head -n1)
                CANGJIE_STDX_PATH="$(pwd -P)/$CANGJIE_STDX_PATH"
                export CANGJIE_STDX_PATH
            else
                echo "❌ Error: cangjie_compiler/include directory not found, required for stdx build"
                exit 1
            fi
        else
            echo "⚠️  Skipping stdx (optional component not found)"
        fi

        # Build cjpm tools (optional)
        if [ -d "$MY_ROOT/cangjie_tools/cjpm" ]; then
            echo "Building cjpm tools (optional)..."
            cd $MY_ROOT/cangjie_tools/cjpm
            if [ "$CLEAN_BUILD" = true ]; then
                python3 build/build.py clean
            fi
            python3 build/build.py build -t $BUILD_TYPE
            python3 build/build.py install
            python3 build/build.py install --prefix $CANGJIE_HOME/tools/bin
            echo "✅ cjpm tools build completed"
        else
            echo "⚠️  Skipping cjpm tools (optional component not found)"
        fi
        ;;
esac

echo ""
echo "✅ Build completed successfully!"

# Calculate and display total time
END_TIME=$(date +%s)
show_elapsed_time $END_TIME $START_TIME
